/*
 * Copyright (c) 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 */
package net.sourceforge.perforce.ui.prefs;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sourceforge.perforce.ui.internal.Policy;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.ListSelectionDialog;

/**
  * @version $Revision: 75 $
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
class FormatFieldEditor extends StringFieldEditor 
{
	// --------------------------------------------------------------------------- Private Variables
	
	/** Stores the reference to the FieldEditor's button control. */
	private Button buttonControl;
	/** Stores the bindings dor the add variables dialog. */
	private Map bindings;
	
	// ------------------------------------------------------------------------- Public Constructors
	
	/** Constructor for FormatFieldEditor. */
	public FormatFieldEditor(
		String name, String labelText, String buttonText, Map newBindings, Composite parent) 
	{
		super(name, labelText, parent);
		
		bindings = newBindings;
		getButtonControl(parent).setText(buttonText);
	}
	
	// ------------------------------------------------------------------------------ Public Methods
	
	/** @see org.eclipse.jface.preference.StringFieldEditor#getNumberOfControls() */
	public int getNumberOfControls() 
	{
		return super.getNumberOfControls() + 1;
	}
	
	/** @see FieldEditor#createControl(org.eclipse.swt.widgets.Composite) */
	protected void createControl(Composite parent) 
	{
		GridLayout layout = (GridLayout) parent.getLayout();
		doFillIntoGrid(parent, layout.numColumns);
	}
	
	/** Returns the FielEditor's button control.
	  * <p>
	  * The control is created if it does not yet exist
	  * </p>
	  *
	  * @param parent the parent
	  * @return the text control
	  */
	public Button getButtonControl(Composite parent)
	{
		if (buttonControl == null)
		{
			buttonControl = new Button(parent, SWT.NONE);
			
			GridData data = new GridData();
			data.horizontalAlignment = GridData.FILL;
			data.heightHint = 
				convertVerticalDLUsToPixels(buttonControl, IDialogConstants.BUTTON_HEIGHT);
			int widthHint = 
				convertHorizontalDLUsToPixels(buttonControl, IDialogConstants.BUTTON_WIDTH);
			data.widthHint = 
				Math.max(widthHint, buttonControl.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
			buttonControl.setLayoutData(data);
			buttonControl.addListener(SWT.Selection, new Listener() 
			{
				public void handleEvent (Event event) 
				{
					addVariables();
				}			
			});
			
		}
		else
		{
			checkParent(buttonControl, parent);
		}
		
		return buttonControl;
	}
		
	// --------------------------------------------------------------------------- Protected Methods

	/** @see org.eclipse.jface.preference.StringFieldEditor#adjustForNumColumns(int) */
	protected void adjustForNumColumns(int numColumns) 
	{
		super.adjustForNumColumns(numColumns - 1);
	}

	
	/** @see StringFieldEditor#doFillIntoGrid(org.eclipse.swt.widgets.Composite, int) */
	protected void doFillIntoGrid(Composite parent, int numColumns) 
	{
		super.doFillIntoGrid(parent, numColumns - 1);
		getButtonControl(parent);
	}
	
	// --------------------------------------------------------------------------- Private Variables
	
	/** Displays the add variables dialog and adds the selected variables to the format
	  * control, 
	  */
	private void addVariables() 
	{	
		ILabelProvider labelProvider = new LabelProvider() 
		{
			public String getText(Object element) 
			{
				StringPair stringPair = (StringPair) element;
				return stringPair.getName() + " - " + stringPair.getDescription();     //$NON-NLS-1$
			}
		};

		final StringPair[] variables = getStringPairs();		
		IStructuredContentProvider contentsProvider = new IStructuredContentProvider() 
		{
			public Object[] getElements(Object inputElement) 
			{
				return variables;
			}
			
			public void dispose() 
			{
			}
			
			public void inputChanged(Viewer viewer, Object oldInput, Object newInput) 
			{
			}
		};
			
		Shell shell = getTextControl().getShell();
		String message =
			Policy.bind(
				"FormatFieldEditor." +                                                 //$NON-NLS-1$
				"Select_the_&variables_to_add_to_the_decoration_format");              //$NON-NLS-1$ 
		ListSelectionDialog dialog = 
			new ListSelectionDialog(shell, this, contentsProvider, labelProvider, message);
				
		dialog.setTitle(Policy.bind("FormatFieldEditor.Add_Variables"));               //$NON-NLS-1$
		if (dialog.open() != Dialog.OK)
		{
			return;
		}
	
		Object[] result = dialog.getResult();		
		for (int i = 0; i < result.length; i++) 
		{
			getTextControl().insert('{' + ((StringPair) result[i]).getName() + '}');
		}		
	}

	/** Create a StringPair array of the editor's bindings.
	  *
	  * @return the StringPair array. 
	  */
	private StringPair[] getStringPairs() 
	{
		final List result = new ArrayList(bindings.size());
		for (Iterator it = bindings.keySet().iterator(); it.hasNext();) 
		{
			String first = (String) it.next();
			
			StringPair variable = new StringPair(first, (String) bindings.get(first));
			result.add(variable);				
		}
		
		return (StringPair[]) result.toArray(new StringPair[result.size()]);
	}
	
	// ---------------------------------------------------------------------- Private Nested Classes
	
	/** Maintains the relationship between a binding and its description. */
	private static class StringPair
	{
		// ----------------------------------------------------------------------- Private Variables
		
		/** Stores the binding */
		private String name;
		/** Stores the description. */
		private String description;
		
		// --------------------------------------------------------------------- Public Constructors
		
		/** Constructor for StringPair. */
		public StringPair(String newName, String newDescription)
		{
			name = newName;
			description = newDescription;
		}
		
		// -------------------------------------------------------------------------- Public Methods
		
		/** Returns the name of the binding.
		  *
		  * @return the binding's name. 
		  */
		public String getName()
		{
			return name;
		}
		
		/** Returns the description of the binding.
		  *
		  * @return the binding's description. 
		  */
		public String getDescription()
		{
			return description;
		}
	}
}
